package xyz.hubery.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.MimeTypeUtils;
import org.springframework.util.StringUtils;
import xyz.hubery.domain.*;
import xyz.hubery.dto.FreezeDTO;
import xyz.hubery.dto.LockUserAmountDTO;
import xyz.hubery.enums.AsyncTaskStatus;
import xyz.hubery.enums.AsyncTaskType;
import xyz.hubery.enums.OrderStatus;
import xyz.hubery.feign.AccountServiceFeign;
import xyz.hubery.mapper.AsyncTaskMapper;
import xyz.hubery.model.Constant;
import xyz.hubery.service.ConfigService;
import xyz.hubery.stream.Source;
import xyz.hubery.service.EntrustOrderService;
import xyz.hubery.mapper.EntrustOrderMapper;
import org.springframework.stereotype.Service;
import xyz.hubery.service.MarketService;
import xyz.hubery.service.TurnoverOrderService;
import xyz.hubery.domain.AsyncTask;
import xyz.hubery.vo.TradeEntrustOrderVo;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author huber
 * @description 针对表【entrust_order(委托订单信息)】的数据库操作Service实现
 * @createDate 2025-10-16 07:45:08
 */
@Service
public class EntrustOrderServiceImpl extends ServiceImpl<EntrustOrderMapper, EntrustOrder>
        implements EntrustOrderService {

    @Autowired
    private Source source;
    @Autowired
    private TurnoverOrderService turnoverOrderService;
    @Autowired
    private MarketService marketService;
    @Autowired
    private AccountServiceFeign accountServiceFeign;
    @Autowired
    private ConfigService configService;
    @Autowired
    EntrustOrderMapper entrustOrderMapper;
    @Autowired
    private AsyncTaskMapper asyncTaskMapper;

    @Override
    public Page<EntrustOrder> findByPage(Page<EntrustOrder> page, Long userId, String symbol, Integer type) {
        return page(page, new LambdaQueryWrapper<EntrustOrder>()
                .eq(userId != null, EntrustOrder::getUserId, userId)
                .eq(!StringUtils.isEmpty(symbol) && !"0".equals(symbol), EntrustOrder::getSymbol, symbol)
                .eq(type != null && type != 0, EntrustOrder::getType, type)
                .orderByDesc(EntrustOrder::getCreated)
        );
    }


    @Override
    public Page<TradeEntrustOrderVo> findHistoryTradeEntrustOrder(Page<EntrustOrder> page, Long userId, String symbol) {
        Page<EntrustOrder> entrustOrderPage = page(page, new LambdaQueryWrapper<EntrustOrder>()
                .eq(EntrustOrder::getUserId, userId)
                .eq(EntrustOrder::getSymbol, symbol)
                .orderByDesc(EntrustOrder::getCreated)
        );
        Page<TradeEntrustOrderVo> resultPage = new Page<>();

        List<EntrustOrder> records = entrustOrderPage.getRecords();
        resultPage.setTotal(entrustOrderPage.getTotal());
        resultPage.setSize(entrustOrderPage.getSize());
        resultPage.setCurrent(entrustOrderPage.getCurrent());

        if (CollectionUtils.isEmpty(records)) {
            return resultPage;
        }

        // 将数据转换为TradeEntrustOrderVo对象
        List<TradeEntrustOrderVo> resultRecodes = new ArrayList<>();
        for (EntrustOrder record : records) {
            TradeEntrustOrderVo vo = new TradeEntrustOrderVo();

            // 设置基础信息
            vo.setOrderId(record.getId());
            vo.setType(record.getType());
            vo.setPrice(record.getPrice());
            vo.setVolume(record.getVolume());
            vo.setAmount(record.getPrice().multiply(record.getVolume()));
            vo.setCreated(record.getCreated());
            vo.setStatus(record.getStatus());

            // 计算实际成交数据（成交订单中获取）
            List<TurnoverOrder> turnoverOrders = turnoverOrderService.findByEntrustOrderId(record.getId(), record.getType());
            BigDecimal dealVolume = BigDecimal.ZERO; // 实际成交量
            BigDecimal dealAmount = BigDecimal.ZERO; // 实际成交额
            for (TurnoverOrder turnoverOrder : turnoverOrders) {
                dealVolume = dealVolume.add(turnoverOrder.getVolume());
                dealAmount = dealAmount.add(turnoverOrder.getAmount());
            }
            if (dealVolume.compareTo(BigDecimal.ZERO) != 0) {
                vo.setDealAvgPrice(dealAmount.divide(dealVolume).setScale(2, RoundingMode.HALF_UP));
            } else {
                vo.setDealAvgPrice(BigDecimal.ZERO);
            }
            vo.setDealVolume(dealVolume);
            vo.setDealAmount(dealAmount);

            resultRecodes.add(vo);
        }

        resultPage.setRecords(resultRecodes);
        return resultPage;
    }

    @Override
    public Page<TradeEntrustOrderVo> findTradeEntrustOrder(Page<EntrustOrder> page, Long userId, String symbol) {
        Page<EntrustOrder> entrustOrderPage = page(page, new LambdaQueryWrapper<EntrustOrder>()
                .eq(EntrustOrder::getUserId, userId)
                .eq(EntrustOrder::getSymbol, symbol)
                .eq(EntrustOrder::getStatus, 0)
                .orderByDesc(EntrustOrder::getCreated)
        );
        Page<TradeEntrustOrderVo> resultPage = new Page<>();

        List<EntrustOrder> records = entrustOrderPage.getRecords();
        resultPage.setTotal(entrustOrderPage.getTotal());
        resultPage.setSize(entrustOrderPage.getSize());
        resultPage.setCurrent(entrustOrderPage.getCurrent());

        if (CollectionUtils.isEmpty(records)) {
            return resultPage;
        }

        // 将数据转换为TradeEntrustOrderVo对象
        List<TradeEntrustOrderVo> resultRecodes = new ArrayList<>();
        for (EntrustOrder record : records) {
            TradeEntrustOrderVo vo = new TradeEntrustOrderVo();

            // 设置基础信息
            vo.setOrderId(record.getId());
            vo.setType(record.getType());
            vo.setPrice(record.getPrice());
            vo.setVolume(record.getVolume());
            vo.setAmount(record.getPrice().multiply(record.getVolume()));
            vo.setCreated(record.getCreated());
            vo.setStatus(record.getStatus());

            // 计算实际成交数据（成交订单中获取）
            List<TurnoverOrder> turnoverOrders = turnoverOrderService.findByEntrustOrderId(record.getId(), record.getType());
            BigDecimal dealVolume = BigDecimal.ZERO; // 实际成交量
            BigDecimal dealAmount = BigDecimal.ZERO; // 实际成交额
            for (TurnoverOrder turnoverOrder : turnoverOrders) {
                dealVolume = dealVolume.add(turnoverOrder.getVolume());
                dealAmount = dealAmount.add(turnoverOrder.getAmount());
            }
            if (dealVolume.compareTo(BigDecimal.ZERO) != 0) {
                vo.setDealAvgPrice(dealAmount.divide(dealVolume).setScale(2, RoundingMode.HALF_UP));
            } else {
                vo.setDealAvgPrice(BigDecimal.ZERO);
            }
            vo.setDealVolume(dealVolume);
            vo.setDealAmount(dealAmount);

            resultRecodes.add(vo);
        }

        resultPage.setRecords(resultRecodes);
        return resultPage;
    }

    @Override
    public void updatecompletedOrders(List<Order> completedOrders) {
        List<EntrustOrder> entrustOrders = new ArrayList<>();
        for (Order order : completedOrders) {
            EntrustOrder entrustOrder = order2EntrustOrder(order);
            if (entrustOrder != null) {
                entrustOrders.add(entrustOrder);
            }
        }
        // 批量更新
        this.updateBatchById(entrustOrders);
    }

    /**
     * Order转EntrustOrder
     *
     * @param order
     */
    private EntrustOrder order2EntrustOrder(Order order) {
        EntrustOrder entrustOrder = this.getById(order.getOrderId());
        if (entrustOrder == null) {
            return null;
        }
        entrustOrder.setDeal(order.getTradedVolume()); // 实际成交数
        entrustOrder.setStatus(1); // 状态为已成交
        return entrustOrder;
    }


    /**
     * 创建一个委托单
     *
     * @param entrustOrder
     * @return
     */
    @Transactional
    @Override
    public boolean createEntrustOrder(EntrustOrder entrustOrder) {
        Market market = marketService.getMarketBySymbol(entrustOrder.getSymbol());
        if (market == null) {
            throw new IllegalArgumentException("交易市场不存在");
        }

        // 校验交易数量
        BigDecimal volume = entrustOrder.getVolume(); // 交易数量
        BigDecimal numMin = market.getNumMin();
        BigDecimal numMax = market.getNumMax();
        if (volume.compareTo(numMin) < 0 || volume.compareTo(numMax) > 0) {
            throw new IllegalArgumentException("交易量不合法");
        }

        // 设置状态为创建中
        entrustOrder.setStatus(OrderStatus.CREATING.getCode());

        // 市场相关数据
        entrustOrder.setMarketId(market.getId());
        entrustOrder.setMarketType(market.getType());
        entrustOrder.setMarketName(market.getName());

        entrustOrder.setAmount(entrustOrder.getPrice().multiply(entrustOrder.getVolume()));

        Config feeRateConfig = configService.getConfigByCode("MAX_FEE_RATE");
        entrustOrder.setFeeRate(new BigDecimal(feeRateConfig.getValue())); // 设置系统最高费率
        entrustOrder.setFee(entrustOrder.getAmount().multiply(entrustOrder.getFeeRate())); // 当前冻结的手续费，与本次账户中冻结数量的一致
        entrustOrder.setDeal(BigDecimal.ZERO);
        entrustOrder.setFreeze(entrustOrder.getAmount().add(entrustOrder.getFee())); // 冻结资金(委托总额+手续费)

        // 新增
        boolean save = save(entrustOrder);

        // TODO  这里通过本地事务+消息表 实现最终一致性 ---> 后续可以跟进为通过Seata TCC强一致实现（可能会使性能变差
        // 扣减账户余额（不直接扣减，而是通过异步补偿机制
        if (save) {
            Long coinId = null;
            if (entrustOrder.getType() == 1) {
                coinId = market.getBuyCoinId();
            } else {
                coinId = market.getSellCoinId();
            }
            // 将可用余额部分冻结
            LockUserAmountDTO dto = new LockUserAmountDTO(entrustOrder.getUserId(), coinId, entrustOrder.getAmount(), "trade_create", entrustOrder.getId(), entrustOrder.getFee());
            AsyncTask asyncTask = new AsyncTask(AsyncTaskType.LOCK_AMOUNT.getType(),JSON.toJSONString(dto),Constant.TASK_MAX_RETRY);
            SecurityContext context = SecurityContextHolder.getContext();
            return asyncTaskMapper.insert(asyncTask) > 0;  // 当前任务与创建订单在同一事物中
//            accountServiceFeign.lockUserAmount(dto);  // 不直接远程调用
        }
        return save;

    }

    /**
     * 类型转换
     *
     * @param exchangeTrade 成交记录
     * @return 更新后的委托单
     */
    @Override
    public List<EntrustOrder> exchangeTrade2EntrustOrder(ExchangeTrade exchangeTrade) {
        // 查询买方委托单
        EntrustOrder buyEntrustOrder = getById(exchangeTrade.getBuyOrderId());
        // 卖方委托单
        EntrustOrder sellEntrustOrder = getById(exchangeTrade.getSellOrderId());
        if (buyEntrustOrder == null || sellEntrustOrder == null) {
            log.error("交易双方委托单异常,{},{}" + exchangeTrade.getBuyOrderId() + exchangeTrade.getSellOrderId());
            return null;
        }
        // 更新实际成交的数据
        BigDecimal volume = exchangeTrade.getVolume(); // 成交数量
        buyEntrustOrder.setDeal(buyEntrustOrder.getDeal().add(volume));
        sellEntrustOrder.setDeal(sellEntrustOrder.getDeal().add(volume));
        if (buyEntrustOrder.getDeal().compareTo(buyEntrustOrder.getVolume()) >= 0) {
            buyEntrustOrder.setStatus(1); // 订单已完成
        }
        if (sellEntrustOrder.getDeal().compareTo(sellEntrustOrder.getVolume()) >= 0) {
            sellEntrustOrder.setStatus(1);
        }
        // 冻结资金变化(解冻
        buyEntrustOrder.setFreeze(buyEntrustOrder.getFeeRate().multiply(exchangeTrade.getBuyTurnover()));
        sellEntrustOrder.setFreeze(sellEntrustOrder.getFeeRate().multiply(exchangeTrade.getSellTurnover()));
        return Arrays.asList(buyEntrustOrder, sellEntrustOrder);
    }

    /**
     * 发送撤销一个委托单消息
     *  不直接更新数据库委托单状态，而是先发送消息通知撮合服务删除该订单
     *  接收到撮合服务删除成功消息后再更新数据库，如果没有收到消息说明该订单已经完全成交，不能删除
     * @param id 委托单id
     * @return
     */
    @Override
    public void sendCancelOrderMessage(Long id) {
        // 使用行锁，防止过程中其他线程修改
        EntrustOrder entrustOrder = getOne(new LambdaQueryWrapper<EntrustOrder>().eq(EntrustOrder::getId, id).last("FOR UPDATE"));
        if(entrustOrder == null || entrustOrder.getStatus() != OrderStatus.OPEN.getCode()){
            throw new RuntimeException("订单异常或已完成交易，不能撤销");
        }
        entrustOrder.setStatus(OrderStatus.CANCELED.getCode()); // 设置状态为取消，这里没有更新数据库，仅仅是为了撮合服务可以进行判断
        MessageBuilder<EntrustOrder> builder = MessageBuilder.withPayload(entrustOrder).setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON);
        source.remOrderOut().send(builder.build());
    }

    //    /**
//     * 撤销一个委托单
//     * @param id 委托单id
//     * @return
//     */
//    @Transactional // 打包成一个事务
//    @Override
//    public boolean cancelOrder(Long id) {
//        // 1、获取行锁(撤销过程中不允许其他线程修改该行数据
//        EntrustOrder entrustOrder = entrustOrderMapper.selectForUpdate(id);
//
//        if (entrustOrder == null) {
//            throw new IllegalArgumentException("委托单不存在");
//        }
//        if (entrustOrder.getStatus() != 0) { // 该订单不需要取消或者异常
//            throw new IllegalArgumentException("该订单状态异常");
//        }
//
//        // 2. 更新为中间状态
//        entrustOrder.setStatus(OrderStatus.CANCELING.getCode());
//
//        // 解冻资金
//        BigDecimal freeze = entrustOrder.getFreeze(); // 将当前冻结资金加入到用户账户资产
//        entrustOrder.setFreeze(BigDecimal.ZERO);
//        boolean ok = entrustOrderMapper.updateById(entrustOrder) > 0;
//
//        // 查询货币id
//        Market market = marketService.getMarketBySymbol(entrustOrder.getSymbol());
//        if (market == null) {
//            throw new IllegalArgumentException("交易市场异常");
//        }
//        Long coinId = null;
//        if (entrustOrder.getType() == 1) {
//            coinId = market.getBuyCoinId();
//        } else {
//            coinId = market.getSellCoinId();
//        }
//        FreezeDTO dto = new FreezeDTO();
//        dto.setUserId(entrustOrder.getUserId());
//        dto.setCoinId(coinId);
//        dto.setFreeze(freeze);
//        dto.setOrderId(id);
////        accountServiceFeign.unFreeze(dto);
//        // 3. 插入异步任务记录(通过定时任务解冻资金
//        AsyncTask task = new AsyncTask(AsyncTaskType.UNFREEZE_BALANCE.getType(),JSON.toJSONString(dto),Constant.TASK_MAX_RETRY);
//        asyncTaskMapper.insert(task);
//
//        // 4、这里不立即删除，等到解冻操作实际完成后再进行删除 发送消息到中间件
////        if (ok) {
////            // 告知撮合系统删除该数据
////            MessageBuilder<EntrustOrder> builder = MessageBuilder.withPayload(entrustOrder).setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON);
////            source.remOrderOut().send(builder.build());
////        }
//
//        return ok;
//    }
}




